﻿/**************************************************************************\
    Copyright Microsoft Corporation. All Rights Reserved.
\**************************************************************************/

namespace Microsoft.Communications.Contacts.Tests
{
    using System;
    using Microsoft.Communications.Contacts;
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using Standard;

    // Disambiguate Standard.Assert
    using Assert = Microsoft.VisualStudio.TestTools.UnitTesting.Assert;

    [TestClass]
    public class PersonTests
    {
        [
            TestMethod,
            Description("Basic test to validate the syntax and semantics for describing a relationship between two contacts.")    
        ]
        public void MapContactRelationships()
        {
            try
            {
                using (ContactManager cm = new ContactManager("*\\PersonTests"))
                {
                    Contact ender = cm.CreateContact();
                    ender.Names.Default = "Ender Wiggin";
                    ender.CommitChanges();

                    Contact dad = cm.CreateContact();
                    dad.Names.Default = "John Paul Wiggin";
                    dad.CommitChanges();

                    Contact olderBrother = cm.CreateContact();
                    olderBrother.Names.Default = "Peter Wiggin";
                    //olderBrother.CommitChanges();

                    // Can add people to the collection, even if they haven't yet been committed to the store.
                    ender.People.Add(
                        new PersonBuilder
                        {
                            ContactId = olderBrother.Id,
                        },
                        PersonLabels.Sibling);
                    // null implies just use the name from the resolved contact.
                    ender.People.Add(new Person(null, dad.Id), PersonLabels.Parent);

                    // Can add people who will never be part of the store.
                    Person sister = new Person("Valentine Wiggin", null);
                    ender.People.Add(sister, PersonLabels.Sibling);

                    Assert.AreEqual(dad.Names.Default, cm.GetContact(ender.People[PersonLabels.Parent].Id).Names.Default);
                    var siblings = ender.GetPropertyCollection(PropertyNames.PersonCollection, new[] { PersonLabels.Sibling }, false).GetEnumerator();
                    Assert.IsTrue(siblings.MoveNext());

                    // Walking the collection with the label filter will give nodes like "PersonCollection/Person[1]", so we need to append the desired property.
                    // Person nodes have /FormattedName and /PersonId
                    // Don't have the Person wrapper when walking the collection like this, so just pull the Id for the first sibling.
                    string id = ender.GetStringProperty(siblings.Current.Name + PropertyNames.PersonId);

                    Contact c;
                    Assert.IsFalse(cm.TryGetContact(id, out c));

                    // After the contact has been committed, it can be resolved.
                    olderBrother.CommitChanges();
                    Assert.IsTrue(cm.TryGetContact(id, out c));
                    Assert.AreEqual(c.Names.Default, olderBrother.Names.Default);

                    Assert.IsTrue(siblings.MoveNext());

                    Assert.AreEqual(ender.GetStringProperty(siblings.Current.Name + PropertyNames.FormattedName), sister.Name);

                    Assert.IsFalse(siblings.MoveNext());

                    // There is also no implicit reciprocal relationship on a contact, even though it may be implied.
                    // It can always be added.
                    Assert.AreEqual(default(Person), dad.People[PersonLabels.Child]);
                }
            }
            finally
            {
                TestUtil.PurgeContactManager("*\\PersonTests");
            }
        }

        [
            TestMethod,
            Description("When a Person is instantiated from a contact it should act as a snapshot view over that contact.")
        ]
        public void ViewContactThroughPerson()
        {
            Person p;
            Name name = new Name("Person");
            EmailAddress address = new EmailAddress("cogito@ergo.sum");

            using (Contact contact = new Contact())
            {
                contact.Names.Add(name);
                contact.EmailAddresses.Add(address);

                p = new Person(contact);

                // The person should reflect the data from the contact when it was made.
                Assert.AreEqual(name.FormattedName, p.Name);
                Assert.AreEqual(address.Address, p.Email);

                contact.Names.RemoveAt(contact.Names.DefaultIndex);
                Assert.AreEqual(name.FormattedName, p.Name);
                Assert.AreEqual(default(Name), contact.Names.Default);
            }
        }

        [
            TestMethod,
            Description("Persons aren't affected by a backing contact no longer being in memory.")
        ]
        public void ViewDisposedContactThroughPerson()
        {
            Person p = default(Person);
            Name name = new Name("Disposable");

            using (Contact contact = new Contact())
            {
                contact.Names.Add(name);
                p = new Person(contact, null, "phone", null, null);
            }

            // Backing contact has now been disposed.

            Assert.AreEqual(name.FormattedName, p.Name);
            Assert.AreEqual("phone", p.Phone);
            Assert.AreEqual("", p.Email);
        }

        [
            TestMethod,
            Description("Persons aren't affected by a backing contact no longer being in memory.")
        ]
        public void ExplicitPropertiesOverrideImplicitProperties()
        {
            Person p = default(Person);
            Name name = new Name("throw away");
            PhoneNumber number = new PhoneNumber("206-555-1212");

            using (Contact contact = new Contact())
            {
                contact.Names.Add(name);
                contact.PhoneNumbers.Add(number, PhoneLabels.Cellular, PropertyLabels.Business);

                p = new Person(contact, null, "phone", null, null);

                Assert.AreEqual(name.FormattedName, p.Name);

                Assert.AreEqual("phone", p.Phone);
                Assert.AreEqual("", p.Email);
            }
        }

        [TestMethod]
        public void SetPersonOnContact()
        {
            using (Contact member = new Contact())
            {
 
            }
        }

        [TestMethod]
        public void BuildPersonFromBuilder()
        {
            using (Contact contact = new Contact())
            {
                PersonBuilder builder = new PersonBuilder("Person", contact.Id);
                contact.EmailAddresses.Default = new EmailAddress("Email");

                // Explicitly set phone, it should round-trip.
                builder.Phone = "Phone";
                Assert.AreEqual("Phone", builder.Phone);

                // E-mail is implicitly set,
                // it should only be inferred when a Person backed by a committed contact.
                Assert.IsNull(builder.Email);

                Person p = builder;
                Assert.AreEqual(builder.Phone, p.Phone);
                Assert.AreEqual("", p.Email);
            }
        }

        [TestMethod]
        public void InferPropertiesFromId()
        {
            // Tokens are case sensitive.  User's should never really be generating these though.
            string singlePhone = "206-555-1212";
            string singleEmail = "Eml@microsoft.com";
            string goodId = "/PHONE:\"" + singlePhone + "\" /IGNORE:\"OMG! PONIES!!1!\" /EMAIL:\"" + singleEmail + "\"";

            Person p = new Person(null, goodId, null);
            Assert.AreEqual(ContactTypes.None, p.ContactType);
            Assert.AreEqual(singleEmail, p.Email);
            Assert.AreEqual(singlePhone, p.Phone);
            Assert.AreEqual("", p.Name);

            string badId = "/GUID:\"not really a guid\"";
            p = new Person("Name", badId, null);
            Assert.AreEqual(ContactTypes.None, p.ContactType);
            Assert.AreEqual("", p.Email);
            Assert.AreEqual("", p.Phone);
            Assert.AreEqual("Name", p.Name);
        }
    }
}
